package com.yyoo.doc.mypdf;

import com.lowagie.text.Document;
import com.lowagie.text.FontFactory;
import com.lowagie.text.PageSize;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.PdfCopy;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfWriter;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.function.BiConsumer;

/**
 * pdf 工具类
 * @author zzy
 */
public class MyPdf {

    public static final String ERROR_MSG = "PDF 创建失败";

    private MyPdf(){}

    /**
     * 添加服务器所有字体（字体加载一次就行，可将加载字体方法添加在 静态块中）
     * <BLOCKQUOTE><pre>{@code
     *     registerDirectory("c:/windows/fonts");
     *     registerDirectory("c:/winnt/fonts");
     *     registerDirectory("d:/windows/fonts");
     *     registerDirectory("d:/winnt/fonts");
     *     registerDirectory("/usr/share/X11/fonts", true);
     *     registerDirectory("/usr/X/lib/X11/fonts", true);
     *     registerDirectory("/usr/openwin/lib/X11/fonts", true);
     *     registerDirectory("/usr/share/fonts", true);
     *     registerDirectory("/usr/X11R6/lib/X11/fonts", true);
     *     registerDirectory("/Library/Fonts");
     *     registerDirectory("/System/Library/Fonts");
     * }</pre></BLOCKQUOTE>
     */
    public static void registerServerFont() {
        FontFactory.registerDirectories();
    }

    /**
     * 注册字体目录（字体加载一次就行，可将加载字体方法添加在 静态块中）
     * @param fontDir 字体所在目录
     */
    public static void registerFontDirectory(String fontDir) {
        FontFactory.registerDirectory(fontDir);
    }

    /**
     * 创建 pdf
     * @param pdfOut pdf 输出流
     * @param pageSize 页面大小 (PageSize.A4 或自定义)
     * @param consumer pdf 创建执行过程（比如 使用 Html2Pdf 将 html 转换后输出到当前 pdf 或者自定义编码实现 pdf 的创建）
     * @param userPass 用户密码
     * @param ownerPass 拥有者密码
     * @param permissions 类似 PdfWriter.ALLOW_COPY | PdfWriter.ALLOW_PRINTING | PdfWriter.ALLOW_MODIFY_CONTENTS
     */
    public static void createPdf(OutputStream pdfOut,
                                 Rectangle pageSize,
                                 byte[] userPass, byte[] ownerPass, int permissions,
                                 BiConsumer<PdfWriter,Document> consumer){
        try(Document document = new Document(pageSize)) {
            final PdfWriter instance =  PdfWriter.getInstance(document, pdfOut);
            if(userPass != null || ownerPass != null) {
                instance.setEncryption(userPass, ownerPass, permissions, PdfWriter.STANDARD_ENCRYPTION_128);
            }
            consumer.accept(instance,document);

        }catch (Exception e){
            throw new MyPdfException(ERROR_MSG,e);
        }
    }

    /**
     * 创建 pdf
     * @param pdfOut pdf 输出流
     * @param pageSize 页面大小 (PageSize.A4 或自定义)
     * @param consumer pdf 创建执行过程（比如 使用 Html2Pdf 将 html 转换后输出到当前 pdf 或者自定义编码实现 pdf 的创建）
     */
    public static void createPdf(OutputStream pdfOut,Rectangle pageSize, BiConsumer<PdfWriter,Document> consumer){
        createPdf(pdfOut, pageSize,null,null,-100,consumer);
    }

    /**
     * 创建 pdf
     * @param pdfOut pdf 输出流
     * @param consumer pdf 创建执行过程（比如 使用 Html2Pdf 将 html 转换后输出到当前 pdf 或者自定义编码实现 pdf 的创建）
     */
    public static void createPdf(OutputStream pdfOut, BiConsumer<PdfWriter,Document> consumer){
        createPdf(pdfOut, PageSize.A4,null,null,-100,consumer);
    }

    /**
     * 创建 pdf
     * @param pdfFilePath pdf 文件路径
     * @param pageSize 页面大小 (PageSize.A4 或自定义)
     * @param consumer pdf 创建执行过程（比如 使用 Html2Pdf 将 html 转换后输出到当前 pdf 或者自定义编码实现 pdf 的创建）
     * @param userPass 用户密码
     * @param ownerPass 拥有者密码
     * @param permissions 类似 PdfWriter.ALLOW_COPY | PdfWriter.ALLOW_PRINTING | PdfWriter.ALLOW_MODIFY_CONTENTS
     */
    public static void createPdf(Path pdfFilePath,Rectangle pageSize,byte[] userPass,byte[] ownerPass,int permissions, BiConsumer<PdfWriter,Document> consumer) {
        try {
            createPdf(Files.newOutputStream(pdfFilePath),pageSize,userPass,ownerPass,permissions,consumer);
        } catch (IOException e) {
            throw new MyPdfException(ERROR_MSG,e);
        }
    }

    /**
     * 创建 pdf
     * @param pdfFilePath pdf 文件路径
     * @param consumer pdf 创建执行过程（比如 使用 Html2Pdf 将 html 转换后输出到当前 pdf 或者自定义编码实现 pdf 的创建）
     * @param userPass 用户密码
     * @param ownerPass 拥有者密码
     * @param permissions 类似 PdfWriter.ALLOW_COPY | PdfWriter.ALLOW_PRINTING | PdfWriter.ALLOW_MODIFY_CONTENTS
     */
    public static void createPdf(Path pdfFilePath,byte[] userPass,byte[] ownerPass,int permissions, BiConsumer<PdfWriter,Document> consumer) {
        try {
            createPdf(Files.newOutputStream(pdfFilePath),PageSize.A4,userPass,ownerPass,permissions,consumer);
        } catch (IOException e) {
            throw new MyPdfException(ERROR_MSG,e);
        }
    }

    /**
     * 创建 pdf
     * @param pdfFilePath pdf 文件路径
     * @param consumer pdf 创建执行过程（比如 使用 Html2Pdf 将 html 转换后输出到当前 pdf 或者自定义编码实现 pdf 的创建）
     */
    public static void createPdf(Path pdfFilePath,Rectangle pageSize, BiConsumer<PdfWriter,Document> consumer) {
        try {
            createPdf(Files.newOutputStream(pdfFilePath),pageSize,null,null,-100,consumer);
        } catch (IOException e) {
            throw new MyPdfException(ERROR_MSG,e);
        }
    }

    /**
     * 创建 pdf
     * @param pdfFilePath pdf 文件路径
     * @param consumer pdf 创建执行过程（比如 使用 Html2Pdf 将 html 转换后输出到当前 pdf 或者自定义编码实现 pdf 的创建）
     */
    public static void createPdf(Path pdfFilePath, BiConsumer<PdfWriter,Document> consumer) {
        try {
            createPdf(Files.newOutputStream(pdfFilePath),PageSize.A4,null,null,-100,consumer);
        } catch (IOException e) {
            throw new MyPdfException(ERROR_MSG,e);
        }
    }

    /**
     * 合并 pdf
     * @param pdfFilePath 合并后的 pdf 文件路径
     * @param pdfFiles 合并前的 pdf 列表
     */
    public static void merge(Path pdfFilePath,Path...pdfFiles){
        try(Document document = new Document();
            PdfCopy copy = new PdfCopy(document, Files.newOutputStream(pdfFilePath))) {
            document.open();
            for (Path pdf : pdfFiles) {
                try(PdfReader pdfreader = new PdfReader(Files.newInputStream(pdf))) {
                    int n = pdfreader.getNumberOfPages();
                    for (int i = 1; i <= n; i++) {
                        copy.addPage(copy.getImportedPage(pdfreader, i));
                    }
                    copy.freeReader(pdfreader);
                }
            }

        }catch (Exception e){
            throw new MyPdfException(ERROR_MSG,e);
        }
    }

}
